﻿#region License
/* Copyright (C) 2009 Tim Coulter
 * 
 * This file is part of ExtremeML.
 * 
 * ExtremeML is free software: you can redistribute
 * it and/or modify it under the terms of the GNU General Public
 * License, as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 * 
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
 * the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses/.
*/
#endregion

using System;
using System.Collections.Generic;
using DocumentFormat.OpenXml;

namespace ExtremeML.Core
{
	/// <summary>
	/// Serves as the base class for classes that maintain collections of <see cref="ElementWrapper{TWrapped}"/>.
	/// </summary>
	public abstract class ElementWrapperCollection<TMember, TInner> : WrapperCollection<OpenXmlElement, TMember, TInner>
		where TMember : ElementWrapper<TInner>
		where TInner : OpenXmlElement, new()
	{
		#region Housekeeping

		/// <summary>
		/// Initializes a new instance of the <see cref="ElementWrapperCollection{TMember, TInner}"/> class.
		/// </summary>
		/// <param name="wrapped">An <see cref="OpenXmlElement"/> from which to populate this instance.</param>
		/// <param name="parent">An <see cref="IContentWrapper"/> that represents the parent wrapper instance.</param>
		/// <param name="package">An <see cref="IContentWrapper"/> that represents the package wrapper instance.</param>
		protected ElementWrapperCollection(
			OpenXmlElement wrapped,
			IContentWrapper parent,
			IContentWrapper package)
			: base(wrapped, parent, package)
		{
		}

		#endregion
		#region Properties


		#endregion
		#region Overrides


		#endregion
		#region Life-Cycle Methods


		#endregion
		#region Content Management Methods

		/// <summary>
		/// Creates a new wrapper instance, representing a new wrapped content object class and adds it to the collection.
		/// </summary>
		/// <returns>A new instance of the member wrapper type.</returns>
		internal TMember Add()
		{
			var result = CreateDefaultMemberWrapper();
			OnCustomAdding(result);
			Items.Add(result);
			return result;
		}

		/// <summary>
		/// Creates a new wrapper instance, representing a new instance of the wrapped class and
		/// adds it to the contained collection before the specified existing collection member.
		/// </summary>
		/// <param name="element">A member wrapper instance to insert before.</param>
		/// <returns>A new instance of the member wrapper type.</returns>
		internal TMember AddBefore(
			TMember element)
		{
			if (Items.Contains(element))
			{
				return AddAt(Items.IndexOf(element));
			}
			else
			{
				throw new KeyNotFoundException();
			}
		}

		/// <summary>
		/// Creates a new wrapper instance, representing a new instance of the wrapped
		/// class and adds it to the contained collection at the specified index.
		/// </summary>
		/// <param name="index">The 0-based index at which to add the new element.</param>
		/// <returns>A new instance of the member wrapper type.</returns>
		internal TMember AddAt(
			int index)
		{
			if (Items.Count > index)
			{
				var result = CreateDefaultMemberWrapper();
				OnCustomAdding(result);
				Items.Insert(index, result);
				return result;
			}
			else
			{
				throw new IndexOutOfRangeException();
			}
		}

		/// <summary>
		/// Removes all the members from the collection.
		/// </summary>
		internal override void Clear()
		{
			var items = new List<TMember>(Items);

			foreach (var item in items)
			{
				Remove(item);
			}
		}

		/// <summary>
		/// Removes the passed member from the collection.
		/// </summary>
		/// <param name="member">A <see cref="IContentWrapper"/> to remove.</param>
		internal override void Remove(
			IContentWrapper member)
		{
			if (typeof(TMember).IsAssignableFrom(member.GetType()))
			{
				var target = (TMember)member;

				if (Items.Contains(target) && OnCustomRemoving(target))
				{
					Items.Remove(target);
					OnCustomRemoved(target);
				}
			}
		}

		/// <summary>
		/// Removes the member at the specified index from the collection.
		/// </summary>
		/// <param name="index">The zero-based index of the element to remove.</param>
		internal void RemoveAt(
			int index)
		{
			if (Items.Count > index)
			{
				Remove(Items[index]);
			}
			else
			{
				throw new IndexOutOfRangeException();
			}
		}

		#endregion

		/// <summary>
		/// When overridden in a derived class, creates a new member wrapper instance populated with default content.
		/// </summary>
		/// <returns>A new instance of the member wrapper type.</returns>
		protected abstract TMember CreateDefaultMemberWrapper();
	}
}
